library(plotly)
library(dplyr)
#plotly code:
plotlyOutput('pcp')
output$pcp <- renderPlotly({
pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>% unique()
col_names <- sapply(pcdat, is.factor)
pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)
library(plotly)
pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
dimensions = list(
list(range = c(1,50),
tickvals = c(1:50),
label = 'state',
ticktext = c(paste(dat$state)),
values = ~state ),
list(range = c(~min(total),~max(total)),
label = 'total tests',
tickvals = c(~min(total),~max(total)),
values= ~total),
list(range=c(1,2),
tickvals = c(1, 2),
label = 'party',
ticktext = c(paste(party)),
values = ~Governor.Political.Affiliation ),
list(range = c(1,7),
tickvals = c(1,7),
label = 'school closure date',
ticktext = c(paste(dat$StateClosureStartDate)),
values = ~StateClosureStartDate
)
)
)
})
fig <- pcdat %>% plot_ly(width = 1000, height = 600)
#fig %>%
pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>% unique()
col_names <- sapply(pcdat, is.factor)
pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)
library(plotly)
#options(viewer=NULL)
pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
dimensions = list(
list(range = c(1,50),
tickvals = c(1:50),
label = 'state',
ticktext = c(paste(dat$state)),
values = ~state ),
list(range = c(~min(total),~max(total)),
label = 'total tests',
tickvals = c(~min(total),~max(total)),
values= ~total),
list(range=c(1,2),
tickvals = c(1, 2),
label = 'party',
ticktext = c(paste(party)),
values = ~Governor.Political.Affiliation ),
list(range = c(1,7),
tickvals = c(1,7),
label = 'school closure date',
ticktext = c(paste(dat$StateClosureStartDate)),
values = ~StateClosureStartDate
)
)
)
NA
fig <- pcdat %>% plot_ly(width = 1000, height = 600)
#fig %>%
pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>% unique()
col_names <- sapply(pcdat, is.factor)
pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)
library(plotly)
#options(viewer=NULL)
pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
dimensions = list(
list(range = c(1,50),
tickvals = c(1:50),
label = 'state',
ticktext = c(paste(dat$state)),
values = ~state ),
list(range = c(~min(total),~max(total)),
label = 'total tests',
tickvals = c(~min(total),~max(total)),
values= ~total),
list(range=c(1,2),
tickvals = c(1, 2),
label = 'party',
ticktext = c(paste(party)),
values = ~Governor.Political.Affiliation ),
list(range = c(1,7),
tickvals = c(1,7),
label = 'school closure date',
ticktext = c(paste(dat$StateClosureStartDate)),
values = ~StateClosureStartDate
)
)
)
An example parallel coordinate plot to use as a template. This code is from Plotly documentation: https://plotly.com/r/parallel-coordinates-plot/
df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/parcoords_data.csv")
fig <- df %>%
plot_ly(width = 1000, height = 600)
fig <- fig %>% add_trace(type = 'parcoords',
# line = list(color = ~colorVal,
# colorscale = 'Jet',
# showscale = TRUE,
# reversescale = TRUE,
# cmin = -4000,
# cmax = -100),
dimensions = list(
list(range = c(~min(blockHeight),~max(blockHeight)),
constraintrange = c(100000,150000),
label = 'Block Height', values = ~blockHeight),
list(range = c(~min(blockWidth),~max(blockWidth)),
label = 'Block Width', values = ~blockWidth),
list(tickvals = c(0,0.5,1,2,3),
ticktext = c('A','AB','B','Y','Z'),
label = 'Cyclinder Material', values = ~cycMaterial),
list(range = c(-1,4),
tickvals = c(0,1,2,3),
label = 'Block Material', values = ~blockMaterial),
list(range = c(~min(totalWeight),~max(totalWeight)),
visible = TRUE,
label = 'Total Weight', values = ~totalWeight),
list(range = c(~min(assemblyPW),~max(assemblyPW)),
label = 'Assembly Penalty Weight', values = ~assemblyPW),
list(range = c(~min(HstW),~max(HstW)),
label = 'Height st Width', values = ~HstW),
list(range = c(~min(minHW),~max(minHW)),
label = 'Min Height Width', values = ~minHW),
list(range = c(~min(minWD),~max(minWD)),
label = 'Min Width Diameter', values = ~minWD),
list(range = c(~min(rfBlock),~max(rfBlock)),
label = 'RF Block', values = ~rfBlock)
)
)
fig
head(df)
On to our code. Merge the two datasets and join them on the state abbreviation.
Define the regions based on CDC standards:
#define regions based on CDC standards (https://www.cdc.gov/coronavirus/2019-ncov/covid-data/covidview/04102020/labs-regions.html)
R1 <- c('CT', 'ME', 'MA', 'NH', 'RI', 'VT')
R2 <- c('NJ', 'NY', 'PR')
R3 <- c('DE', 'DC', 'MD', 'PA', 'VA', 'WV')
R4 <- c('AL', 'FL', 'GA', 'KY', 'MS', 'NC', 'SC', 'TN')
R5 <- c('IL', 'IN', 'MI','MN','OH','WI')
R6 <- c('AR','LA','NM','OK','TX')
R7 <- c('IA', 'KS', 'MO', 'NE')
R8 <- c('CO', 'MT', 'ND','SD','UT','WY')
R9 <- c('AZ', 'CA', 'GU', 'HI','NV')
R10 <- c('AK','ID','OR','WA')
#put as character so that all states/territories have a value and all values of same type of vector
dat <- dat %>% mutate(region = (
case_when(state %in% R1 ~ '1',
state %in% R2 ~ '2',
state %in% R3 ~ '3',
state %in% R4 ~ '4',
state %in% R5 ~ '5',
state %in% R6 ~ '6',
state %in% R7 ~ '7',
state %in% R8 ~ '8',
state %in% R9 ~ '9',
state %in% R10 ~ '10',
TRUE ~ 'Other')
))
#Reference Documentation : https://plotly.com/r/reference/#parcoords
#DO NOT RUN YET. have not updated completely
fig <- dat %>%
plot_ly(width = 1000, height = 600)
fig <- fig %>% add_trace(type = 'parcoords', name = ~state,
dimensions = list(
list(tickvals = c(0:50),
ticktext = c(dat$state),
label = 'State', values = ~state),
list(
range=c(~min(totalTestResults), ~max(totalTestResults)),
label = 'Total Tests',
values = ~totalTestResults)
# list(range = c(~min(blockHeight),~max(blockHeight)),
# constraintrange = c(100000,150000),
# label = 'Block Height', values = ~blockHeight),
# list(range = c(~min(blockWidth),~max(blockWidth)),
# label = 'Block Width', values = ~blockWidth),
# list(tickvals = c(0,0.5,1,2,3),
# ticktext = c('A','AB','B','Y','Z'),
# label = 'Cyclinder Material', values = ~cycMaterial),
# list(range = c(-1,4),
# tickvals = c(0,1,2,3),
# label = 'Block Material', values = ~blockMaterial),
# list(range = c(~min(totalWeight),~max(totalWeight)),
# visible = TRUE,
# label = 'Total Weight', values = ~totalWeight),
# list(range = c(~min(assemblyPW),~max(assemblyPW)),
# label = 'Assembly Penalty Weight', values = ~assemblyPW),
# list(range = c(~min(HstW),~max(HstW)),
# label = 'Height st Width', values = ~HstW),
# list(range = c(~min(minHW),~max(minHW)),
# label = 'Min Height Width', values = ~minHW),
# list(range = c(~min(minWD),~max(minWD)),
# label = 'Min Width Diameter', values = ~minWD),
# list(range = c(~min(rfBlock),~max(rfBlock)),
# label = 'RF Block', values = ~rfBlock)
)
)
fig
GGally more difficult to do categorical data, but way to separate out groups, scale the data (univariately, substract mean & divide by sd)
library(GGally)
dat %>% arrange(desc(region))%>%
ggparcoord(
columns = c(18,29), groupColumn = 32
) +
scale_color_manual(values=c( "#69b3a2", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8") )
#can factor regions
#dat %>% colnames()
THIS ONE!! cdparcoord
LS0tCnRpdGxlOiAiNzA2IFBhcmFsbGVsIENvb3JkaW5hdGVzIgphdXRob3I6ICdEYW55IFRob3JwZSBIdWVydGEnCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShkcGx5cikKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQojcGxvdGx5IGNvZGU6CnBsb3RseU91dHB1dCgncGNwJykKCm91dHB1dCRwY3AgPC0gcmVuZGVyUGxvdGx5KHsKICAgICAgICAKICAgICAgcGNkYXQ8LSBkYXRbMTo1NCxjKDIsMTgsMjcsIDI5KV0gJT4lIHN1YnNldCghaXMubmEoZGF0WzE6NTQsMjldKSkKICAgICAgcGFydHkgPC1kYXRbMTo1NCwyOV0gJT4lIHN1YnNldCghaXMubmEoZGF0WywyOV0pKSAlPiUgIHVuaXF1ZSgpIAogICAgICBjb2xfbmFtZXMgPC0gc2FwcGx5KHBjZGF0LCBpcy5mYWN0b3IpCiAgICAgIHBjZGF0Wyxjb2xfbmFtZXNdIDwtIHNhcHBseShwY2RhdFssY29sX25hbWVzXSAsIHVuY2xhc3MpCiAgICAgIAogICAgICBsaWJyYXJ5KHBsb3RseSkgCiAgICAgIHBjZGF0ICU+JSBwbG90X2x5KCkgJT4lIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsIGxpbmUgPSBsaXN0KGNvbG9yID0gfkdvdmVybm9yLlBvbGl0aWNhbC5BZmZpbGlhdGlvbiwgY29sb3JzY2FsZSA9IGxpc3QoYygwLCdibHVlJyksYygxLCdyZWQnKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKDEsNTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYygxOjUwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdzdGF0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3RleHQgPSBjKHBhc3RlKGRhdCRzdGF0ZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IH5zdGF0ZSApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbih0b3RhbCksfm1heCh0b3RhbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3RvdGFsIHRlc3RzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdmFscyA9IGMofm1pbih0b3RhbCksfm1heCh0b3RhbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz0gfnRvdGFsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QocmFuZ2U9YygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYygxLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdwYXJ0eScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3RleHQgPSBjKHBhc3RlKHBhcnR5KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gfkdvdmVybm9yLlBvbGl0aWNhbC5BZmZpbGlhdGlvbiApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMoMSw3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdmFscyA9IGMoMSw3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdzY2hvb2wgY2xvc3VyZSBkYXRlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUoZGF0JFN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IH5TdGF0ZUNsb3N1cmVTdGFydERhdGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgKQogICAgICAKICAgIH0pCmBgYAoKYGBge3J9CiAgZmlnIDwtIHBjZGF0ICU+JSBwbG90X2x5KHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gNjAwKSAKICAgICAgI2ZpZyAlPiUgCiAgICAgIHBjZGF0PC0gZGF0WzE6NTQsYygyLDE4LDI3LCAyOSldICU+JSBzdWJzZXQoIWlzLm5hKGRhdFsxOjU0LDI5XSkpCiAgICAgIHBhcnR5IDwtZGF0WzE6NTQsMjldICU+JSBzdWJzZXQoIWlzLm5hKGRhdFssMjldKSkgJT4lICB1bmlxdWUoKSAKICAgICAgY29sX25hbWVzIDwtIHNhcHBseShwY2RhdCwgaXMuZmFjdG9yKQogICAgICBwY2RhdFssY29sX25hbWVzXSA8LSBzYXBwbHkocGNkYXRbLGNvbF9uYW1lc10gLCB1bmNsYXNzKQogICAgICAKICAgICAgbGlicmFyeShwbG90bHkpIAogICAgICAjb3B0aW9ucyh2aWV3ZXI9TlVMTCkKICAgICAgcGNkYXQgJT4lIHBsb3RfbHkoKSAlPiUgYWRkX3RyYWNlKHR5cGUgPSAncGFyY29vcmRzJywgbGluZSA9IGxpc3QoY29sb3IgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uLCBjb2xvcnNjYWxlID0gbGlzdChjKDAsJ2JsdWUnKSxjKDEsJ3JlZCcpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1lbnNpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMoMSw1MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKDE6NTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3N0YXRlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUoZGF0JHN0YXRlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gfnN0YXRlICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKHRvdGFsKSx+bWF4KHRvdGFsKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAndG90YWwgdGVzdHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYyh+bWluKHRvdGFsKSx+bWF4KHRvdGFsKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPSB+dG90YWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZT1jKDEsMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKDEsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3BhcnR5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUocGFydHkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYygxLDcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYygxLDcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3NjaG9vbCBjbG9zdXJlIGRhdGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYyhwYXN0ZShkYXQkU3RhdGVDbG9zdXJlU3RhcnREYXRlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gflN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICApCiAgICAgIApgYGAKCgpgYGB7cn0KZmlnIDwtIHBjZGF0ICU+JSBwbG90X2x5KHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gNjAwKSAKI2ZpZyAlPiUgCnBjZGF0PC0gZGF0WzE6NTQsYygyLDE4LDI3LCAyOSldICU+JSBzdWJzZXQoIWlzLm5hKGRhdFsxOjU0LDI5XSkpCnBhcnR5IDwtZGF0WzE6NTQsMjldICU+JSBzdWJzZXQoIWlzLm5hKGRhdFssMjldKSkgJT4lICB1bmlxdWUoKSAKY29sX25hbWVzIDwtIHNhcHBseShwY2RhdCwgaXMuZmFjdG9yKQpwY2RhdFssY29sX25hbWVzXSA8LSBzYXBwbHkocGNkYXRbLGNvbF9uYW1lc10gLCB1bmNsYXNzKQoKbGlicmFyeShwbG90bHkpIAojb3B0aW9ucyh2aWV3ZXI9TlVMTCkKcGNkYXQgJT4lIHBsb3RfbHkoKSAlPiUgYWRkX3RyYWNlKHR5cGUgPSAncGFyY29vcmRzJywgbGluZSA9IGxpc3QoY29sb3IgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uLCBjb2xvcnNjYWxlID0gbGlzdChjKDAsJ2JsdWUnKSxjKDEsJ3JlZCcpKSksCmRpbWVuc2lvbnMgPSBsaXN0KAogIGxpc3QocmFuZ2UgPSBjKDEsNTApLAogICAgICAgdGlja3ZhbHMgPSBjKDE6NTApLAogICAgICAgbGFiZWwgPSAnc3RhdGUnLAogICAgICAgdGlja3RleHQgPSBjKHBhc3RlKGRhdCRzdGF0ZSkpLAogICAgICAgdmFsdWVzID0gfnN0YXRlICksCiAgCiAgbGlzdChyYW5nZSA9IGMofm1pbih0b3RhbCksfm1heCh0b3RhbCkpLAogICAgICAgbGFiZWwgPSAndG90YWwgdGVzdHMnLAogICAgICAgdGlja3ZhbHMgPSBjKH5taW4odG90YWwpLH5tYXgodG90YWwpKSwKICAgICAgIHZhbHVlcz0gfnRvdGFsKSwKCmxpc3QocmFuZ2U9YygxLDIpLAogICAgIHRpY2t2YWxzID0gYygxLCAyKSwKICAgICBsYWJlbCA9ICdwYXJ0eScsCiAgICAgdGlja3RleHQgPSBjKHBhc3RlKHBhcnR5KSksCiAgICAgdmFsdWVzID0gfkdvdmVybm9yLlBvbGl0aWNhbC5BZmZpbGlhdGlvbiApLAoKbGlzdChyYW5nZSA9IGMoMSw3KSwKICAgICB0aWNrdmFscyA9IGMoMSw3KSwKICAgICBsYWJlbCA9ICdzY2hvb2wgY2xvc3VyZSBkYXRlJywKICAgICB0aWNrdGV4dCA9IGMocGFzdGUoZGF0JFN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZSkpLAogICAgIHZhbHVlcyA9IH5TdGF0ZUNsb3N1cmVTdGFydERhdGUKICAgICAgICAgICAgICAgICAgKQogICAgICkKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAKKQoKYGBgCgpBbiBleGFtcGxlIHBhcmFsbGVsIGNvb3JkaW5hdGUgcGxvdCB0byB1c2UgYXMgYSB0ZW1wbGF0ZS4gVGhpcyBjb2RlIGlzIGZyb20gUGxvdGx5IGRvY3VtZW50YXRpb246IGh0dHBzOi8vcGxvdGx5LmNvbS9yL3BhcmFsbGVsLWNvb3JkaW5hdGVzLXBsb3QvCmBgYHtyIFRlbXBsYXRlfQpkZiA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2JjZHVuYmFyL2RhdGFzZXRzL21hc3Rlci9wYXJjb29yZHNfZGF0YS5jc3YiKQoKZmlnIDwtIGRmICU+JQogIHBsb3RfbHkod2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApIApmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLAogICAgICAgICAgIyBsaW5lID0gbGlzdChjb2xvciA9IH5jb2xvclZhbCwKICAgICAgICAgICMgICAgICAgICAgICAgY29sb3JzY2FsZSA9ICdKZXQnLAogICAgICAgICAgIyAgICAgICAgICAgICBzaG93c2NhbGUgPSBUUlVFLAogICAgICAgICAgIyAgICAgICAgICAgICByZXZlcnNlc2NhbGUgPSBUUlVFLAogICAgICAgICAgIyAgICAgICAgICAgICBjbWluID0gLTQwMDAsCiAgICAgICAgICAjICAgICAgICAgICAgIGNtYXggPSAtMTAwKSwKICAgICAgICAgIGRpbWVuc2lvbnMgPSBsaXN0KAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKGJsb2NrSGVpZ2h0KSx+bWF4KGJsb2NrSGVpZ2h0KSksCiAgICAgICAgICAgICAgICAgY29uc3RyYWludHJhbmdlID0gYygxMDAwMDAsMTUwMDAwKSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdCbG9jayBIZWlnaHQnLCB2YWx1ZXMgPSB+YmxvY2tIZWlnaHQpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKGJsb2NrV2lkdGgpLH5tYXgoYmxvY2tXaWR0aCkpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ0Jsb2NrIFdpZHRoJywgdmFsdWVzID0gfmJsb2NrV2lkdGgpLAogICAgICAgICAgICBsaXN0KHRpY2t2YWxzID0gYygwLDAuNSwxLDIsMyksCiAgICAgICAgICAgICAgICAgdGlja3RleHQgPSBjKCdBJywnQUInLCdCJywnWScsJ1onKSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdDeWNsaW5kZXIgTWF0ZXJpYWwnLCB2YWx1ZXMgPSB+Y3ljTWF0ZXJpYWwpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYygtMSw0KSwKICAgICAgICAgICAgICAgICB0aWNrdmFscyA9IGMoMCwxLDIsMyksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnQmxvY2sgTWF0ZXJpYWwnLCB2YWx1ZXMgPSB+YmxvY2tNYXRlcmlhbCksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4odG90YWxXZWlnaHQpLH5tYXgodG90YWxXZWlnaHQpKSwKICAgICAgICAgICAgICAgICB2aXNpYmxlID0gVFJVRSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdUb3RhbCBXZWlnaHQnLCB2YWx1ZXMgPSB+dG90YWxXZWlnaHQpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKGFzc2VtYmx5UFcpLH5tYXgoYXNzZW1ibHlQVykpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ0Fzc2VtYmx5IFBlbmFsdHkgV2VpZ2h0JywgdmFsdWVzID0gfmFzc2VtYmx5UFcpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKEhzdFcpLH5tYXgoSHN0VykpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ0hlaWdodCBzdCBXaWR0aCcsIHZhbHVlcyA9IH5Ic3RXKSwKICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbihtaW5IVyksfm1heChtaW5IVykpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ01pbiBIZWlnaHQgV2lkdGgnLCB2YWx1ZXMgPSB+bWluSFcpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKG1pbldEKSx+bWF4KG1pbldEKSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnTWluIFdpZHRoIERpYW1ldGVyJywgdmFsdWVzID0gfm1pbldEKSwKICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbihyZkJsb2NrKSx+bWF4KHJmQmxvY2spKSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdSRiBCbG9jaycsIHZhbHVlcyA9IH5yZkJsb2NrKQogICAgICAgICAgICApCiAgICAgICAgICApCgoKZmlnCmBgYAoKYGBge3J9CmhlYWQoZGYpCmBgYAoKT24gdG8gb3VyIGNvZGUuIE1lcmdlIHRoZSB0d28gZGF0YXNldHMgYW5kIGpvaW4gdGhlbSBvbiB0aGUgc3RhdGUgYWJicmV2aWF0aW9uLgpgYGB7ciBSZWFkIERhdGEsIGluY2x1ZGU9RkFMU0V9CmRhdCA8LSByZWFkLmNzdigiLi4vY292aWRfdHJhY2tpbmdfaGlzdG9yeS5jc3YiKQpkYXQkZGF0ZSA8LSBhcy5mYWN0b3IoZGF0JGRhdGUpCgpkYXQgPC0gZGF0ICU+JSBmdWxsX2pvaW4oLiwgcmVhZC5jc3YoIi4uL2Nvcm9uYXZpcnVzLXNjaG9vbC1jbG9zdXJlcy1kYXRhLTQtNy0yMDIwLmNzdiIpLCBieSA9IGMoJ3N0YXRlJyA9ICdTdGF0ZUFiYnJldmlhdGlvbicpKQpkYXQkU3RhdGVDbG9zdXJlU3RhcnREYXRlIDwtIGFzLkRhdGUoZGF0JFN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykKCmBgYAoKRGVmaW5lIHRoZSByZWdpb25zIGJhc2VkIG9uIENEQyBzdGFuZGFyZHM6CmBgYHtyIFJlZ2lvbiBEZWZpbnRpb259CiNkZWZpbmUgcmVnaW9ucyBiYXNlZCBvbiBDREMgc3RhbmRhcmRzIChodHRwczovL3d3dy5jZGMuZ292L2Nvcm9uYXZpcnVzLzIwMTktbmNvdi9jb3ZpZC1kYXRhL2Nvdmlkdmlldy8wNDEwMjAyMC9sYWJzLXJlZ2lvbnMuaHRtbCkKClIxIDwtIGMoJ0NUJywgJ01FJywgJ01BJywgJ05IJywgJ1JJJywgJ1ZUJykKUjIgPC0gYygnTkonLCAnTlknLCAnUFInKQpSMyA8LSBjKCdERScsICdEQycsICdNRCcsICdQQScsICdWQScsICdXVicpClI0IDwtIGMoJ0FMJywgJ0ZMJywgJ0dBJywgJ0tZJywgJ01TJywgJ05DJywgJ1NDJywgJ1ROJykKUjUgPC0gYygnSUwnLCAnSU4nLCAnTUknLCdNTicsJ09IJywnV0knKQpSNiA8LSBjKCdBUicsJ0xBJywnTk0nLCdPSycsJ1RYJykKUjcgPC0gYygnSUEnLCAnS1MnLCAnTU8nLCAnTkUnKQpSOCA8LSBjKCdDTycsICdNVCcsICdORCcsJ1NEJywnVVQnLCdXWScpClI5IDwtIGMoJ0FaJywgJ0NBJywgJ0dVJywgJ0hJJywnTlYnKQpSMTAgPC0gYygnQUsnLCdJRCcsJ09SJywnV0EnKQoKI3B1dCBhcyBjaGFyYWN0ZXIgc28gdGhhdCBhbGwgc3RhdGVzL3RlcnJpdG9yaWVzIGhhdmUgYSB2YWx1ZSBhbmQgYWxsIHZhbHVlcyBvZiBzYW1lIHR5cGUgb2YgdmVjdG9yCmRhdCA8LSBkYXQgJT4lIG11dGF0ZShyZWdpb24gPSAoCiAgY2FzZV93aGVuKHN0YXRlICVpbiUgUjEgfiAnMScsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjIgfiAnMicsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjMgfiAnMycsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjQgfiAnNCcsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjUgfiAnNScsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjYgfiAnNicsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjcgfiAnNycsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjggfiAnOCcsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjkgfiAnOScsCiAgICAgICAgICAgIHN0YXRlICVpbiUgUjEwIH4gJzEwJywgCiAgICAgICAgICAgIFRSVUUgfiAnT3RoZXInKQopKQpgYGAKCgpgYGB7ciBQQ0EgQXR0ZW1wdCwgZXZhbCA9IEZ9CiNSZWZlcmVuY2UgRG9jdW1lbnRhdGlvbiA6IGh0dHBzOi8vcGxvdGx5LmNvbS9yL3JlZmVyZW5jZS8jcGFyY29vcmRzCgojRE8gTk9UIFJVTiBZRVQuIGhhdmUgbm90IHVwZGF0ZWQgY29tcGxldGVseQpmaWcgPC0gZGF0ICU+JQogIHBsb3RfbHkod2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApIApmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLCBuYW1lID0gfnN0YXRlLAogICAgICAgICAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICAgICAgICAgIGxpc3QodGlja3ZhbHMgPSBjKDA6NTApLAogICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYyhkYXQkc3RhdGUpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ1N0YXRlJywgdmFsdWVzID0gfnN0YXRlKSwKICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICByYW5nZT1jKH5taW4odG90YWxUZXN0UmVzdWx0cyksIH5tYXgodG90YWxUZXN0UmVzdWx0cykpLAogICAgICAgICAgICAgIGxhYmVsID0gJ1RvdGFsIFRlc3RzJywKICAgICAgICAgICAgICB2YWx1ZXMgPSB+dG90YWxUZXN0UmVzdWx0cykKICAgICAgICAgICAgCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihibG9ja0hlaWdodCksfm1heChibG9ja0hlaWdodCkpLAogICAgICAgICAgICAjICAgICAgY29uc3RyYWludHJhbmdlID0gYygxMDAwMDAsMTUwMDAwKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ0Jsb2NrIEhlaWdodCcsIHZhbHVlcyA9IH5ibG9ja0hlaWdodCksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihibG9ja1dpZHRoKSx+bWF4KGJsb2NrV2lkdGgpKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ0Jsb2NrIFdpZHRoJywgdmFsdWVzID0gfmJsb2NrV2lkdGgpLAogICAgICAgICAgICAjIGxpc3QodGlja3ZhbHMgPSBjKDAsMC41LDEsMiwzKSwKICAgICAgICAgICAgIyAgICAgIHRpY2t0ZXh0ID0gYygnQScsJ0FCJywnQicsJ1knLCdaJyksCiAgICAgICAgICAgICMgICAgICBsYWJlbCA9ICdDeWNsaW5kZXIgTWF0ZXJpYWwnLCB2YWx1ZXMgPSB+Y3ljTWF0ZXJpYWwpLAogICAgICAgICAgICAjIGxpc3QocmFuZ2UgPSBjKC0xLDQpLAogICAgICAgICAgICAjICAgICAgdGlja3ZhbHMgPSBjKDAsMSwyLDMpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnQmxvY2sgTWF0ZXJpYWwnLCB2YWx1ZXMgPSB+YmxvY2tNYXRlcmlhbCksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbih0b3RhbFdlaWdodCksfm1heCh0b3RhbFdlaWdodCkpLAogICAgICAgICAgICAjICAgICAgdmlzaWJsZSA9IFRSVUUsCiAgICAgICAgICAgICMgICAgICBsYWJlbCA9ICdUb3RhbCBXZWlnaHQnLCB2YWx1ZXMgPSB+dG90YWxXZWlnaHQpLAogICAgICAgICAgICAjIGxpc3QocmFuZ2UgPSBjKH5taW4oYXNzZW1ibHlQVyksfm1heChhc3NlbWJseVBXKSksCiAgICAgICAgICAgICMgICAgICBsYWJlbCA9ICdBc3NlbWJseSBQZW5hbHR5IFdlaWdodCcsIHZhbHVlcyA9IH5hc3NlbWJseVBXKSwKICAgICAgICAgICAgIyBsaXN0KHJhbmdlID0gYyh+bWluKEhzdFcpLH5tYXgoSHN0VykpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnSGVpZ2h0IHN0IFdpZHRoJywgdmFsdWVzID0gfkhzdFcpLAogICAgICAgICAgICAjIGxpc3QocmFuZ2UgPSBjKH5taW4obWluSFcpLH5tYXgobWluSFcpKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ01pbiBIZWlnaHQgV2lkdGgnLCB2YWx1ZXMgPSB+bWluSFcpLAogICAgICAgICAgICAjIGxpc3QocmFuZ2UgPSBjKH5taW4obWluV0QpLH5tYXgobWluV0QpKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ01pbiBXaWR0aCBEaWFtZXRlcicsIHZhbHVlcyA9IH5taW5XRCksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihyZkJsb2NrKSx+bWF4KHJmQmxvY2spKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ1JGIEJsb2NrJywgdmFsdWVzID0gfnJmQmxvY2spCiAgICAgICAgICAgICkKICAgICAgICAgICkKCgpmaWcKYGBgCgpHR2FsbHkKbW9yZSBkaWZmaWN1bHQgdG8gZG8gY2F0ZWdvcmljYWwgZGF0YSwgYnV0IHdheSB0byBzZXBhcmF0ZSBvdXQgZ3JvdXBzLCBzY2FsZSB0aGUgZGF0YSAodW5pdmFyaWF0ZWx5LCBzdWJzdHJhY3QgbWVhbiAmIGRpdmlkZSBieSBzZCkKYGBge3J9CmxpYnJhcnkoR0dhbGx5KQpkYXQgJT4lIGFycmFuZ2UoZGVzYyhyZWdpb24pKSU+JQogICBnZ3BhcmNvb3JkKAogICAgY29sdW1ucyA9IGMoMTgsMjkpLCBncm91cENvbHVtbiA9IDMyCiAgICApICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM2OWIzYTIiLCAiI0U4RThFOCIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIpICkgCgogI2NhbiBmYWN0b3IgcmVnaW9ucwojZGF0ICU+JSBjb2xuYW1lcygpCmBgYAoKVEhJUyBPTkUhISBjZHBhcmNvb3JkCmBgYHtyfQpsaWJyYXJ5KGNkcGFyY29vcmQpCgpkYXRhKGRhdCkKcGNkYXQ8LSBkYXRbMTo1NCxjKDIsMTgsMjksMzIpXSAlPiUgc3Vic2V0KCFpcy5uYShkYXRbMTo1NCwyOV0pKQpkaXNjcGFyY29vcmQocGNkYXQsaz0xNTAsc2F2ZUNvdW50cz1GQUxTRSkgIApgYGAKCgo=